package bigraph;

import java.util.ArrayList;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.parts.ScrollableThumbnail;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.KeyStroke;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.MouseWheelHandler;
import org.eclipse.gef.MouseWheelZoomHandler;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.palette.CombinedTemplateCreationEntry;
import org.eclipse.gef.palette.CreationToolEntry;
import org.eclipse.gef.palette.MarqueeToolEntry;
import org.eclipse.gef.palette.PaletteGroup;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PaletteSeparator;
import org.eclipse.gef.palette.SelectionToolEntry;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.GEFActionConstants;
import org.eclipse.gef.ui.actions.ZoomInAction;
import org.eclipse.gef.ui.actions.ZoomOutAction;
import org.eclipse.gef.ui.parts.ContentOutlinePage;
import org.eclipse.gef.ui.parts.GraphicalEditorWithPalette;
import org.eclipse.gef.ui.parts.TreeViewer;
import org.eclipse.jface.action.IAction;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.IPageSite;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;

import bigraph.model.Canvas;
import bigraph.model.NodeCreationFactory;
import bigraph.model.Place;
import bigraph.model.Root;
import bigraph.model.Site;
import bigraph.part.AppEditPartFactory;
import bigraph.part.tree.AppTreeEditPartFactory;

public class MainViewer extends GraphicalEditorWithPalette {

	private Canvas model;
	private KeyHandler keyHandler;
	public static final String ID = "bigraph.mainviewer";
	public MainViewer() {
	     setEditDomain(new DefaultEditDomain(this));
	}
	
    protected class OutlinePage extends ContentOutlinePage {
    	private ScrollableThumbnail thumbnail;
    	private DisposeListener disposeListener;
    	private SashForm sash;
        public OutlinePage() {
              super(new TreeViewer());
        }
        public void createControl(Composite parent) {
              sash = new SashForm(parent, SWT.VERTICAL);
              getViewer().createControl(sash);
              getViewer().setEditDomain(getEditDomain());
              getViewer().setEditPartFactory(new AppTreeEditPartFactory());
              getViewer().setContents(model);
              getSelectionSynchronizer().addViewer(getViewer());
              
              IActionBars bars = getSite().getActionBars();
              ActionRegistry ar = getActionRegistry();
              bars.setGlobalActionHandler(ActionFactory.COPY.getId(),ar.getAction(ActionFactory.COPY.getId()));
              bars.setGlobalActionHandler(ActionFactory.PASTE.getId(),ar.getAction(ActionFactory.PASTE.getId()));

              //Creation of the miniature
              //Canvas from package Widgets conflicts with bigraph.model.Canvas :/
              org.eclipse.swt.widgets.Canvas canvas = new org.eclipse.swt.widgets.Canvas(sash, SWT.BORDER);
              LightweightSystem lws = new LightweightSystem(canvas);
              thumbnail = new ScrollableThumbnail(
                         (Viewport) ((ScalableRootEditPart) getGraphicalViewer()
                                    .getRootEditPart()).getFigure());
              thumbnail.setSource(((ScalableRootEditPart) getGraphicalViewer()
                         .getRootEditPart())
                         .getLayer(LayerConstants.PRINTABLE_LAYERS));
              lws.setContents(thumbnail);
              disposeListener = new DisposeListener() {
                    @Override
                    public void widgetDisposed(DisposeEvent e) {
                         if (thumbnail != null) {
                                thumbnail.deactivate();
                                thumbnail = null;
                         }
                    }
              };
              getGraphicalViewer().getControl().addDisposeListener(disposeListener);

        }
        
        public void init(IPageSite pageSite) {
              super.init(pageSite);
              IActionBars bars = getSite().getActionBars();
              bars.setGlobalActionHandler(ActionFactory.UNDO.getId(),
            		  getActionRegistry().getAction(ActionFactory.UNDO.getId()));
              bars.setGlobalActionHandler(ActionFactory.REDO.getId(),
            		  getActionRegistry().getAction(ActionFactory.REDO.getId()));
              bars.setGlobalActionHandler(ActionFactory.DELETE.getId(),
            		  getActionRegistry().getAction(ActionFactory.DELETE.getId()));
              bars.updateActionBars();
              getViewer().setKeyHandler(keyHandler);
              ContextMenuProvider provider = new AppContextMenuProvider(getViewer(),getActionRegistry());
              getViewer().setContextMenu(provider);
        }
        
        public Control getControl() {
              return sash;
        }
        
        public void dispose() {
            getSelectionSynchronizer().removeViewer(getViewer());
            if (getGraphicalViewer().getControl() != null
                       && !getGraphicalViewer().getControl().isDisposed())
                  getGraphicalViewer().getControl().removeDisposeListener(disposeListener);
            super.dispose();
        }    
   }

	public Canvas CreateCanvas(){
	     Canvas frame = new Canvas();
	     Root root = new Root();
	     root.setName("Root: 0");
	     root.setLayout(new Rectangle(5,5,300,300));
		 Site site = new Site();
		 site.setName("Site");
		 site.setLayout(new Rectangle(10,10,100,100));
		 root.addChild(site);
	     Place place = new Place();
	     place.setName("Place");
	     place.setLayout(new Rectangle(100,100,150,150));
	     root.addChild(place);
	     frame.addChild(root);
	     
	     return frame;
	}
		
	protected void configureGraphicalViewer() {
	     super.configureGraphicalViewer();
	     GraphicalViewer viewer = getGraphicalViewer();
	     viewer.setEditPartFactory(new AppEditPartFactory());

	     double[] zoomLevels;
	     ArrayList<String> zoomContributions;
	    
	     ScalableRootEditPart rootEditPart = new ScalableRootEditPart();
	     viewer.setRootEditPart(rootEditPart);
         ZoomManager manager = rootEditPart.getZoomManager();
         getActionRegistry().registerAction(new ZoomInAction(manager));
         getActionRegistry().registerAction(new ZoomOutAction(manager));

         //List of possible zoom ranges, 1.0 = 100%
         zoomLevels = new double[] {0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 10.0, 20.0};
         manager.setZoomLevels(zoomLevels);
         zoomContributions = new ArrayList<String>();
         zoomContributions.add(ZoomManager.FIT_ALL);
         zoomContributions.add(ZoomManager.FIT_HEIGHT);
         zoomContributions.add(ZoomManager.FIT_WIDTH);
         manager.setZoomLevelContributions(zoomContributions);
         //initialising the context menu
         ContextMenuProvider provider = new AppContextMenuProvider(viewer,getActionRegistry());
         viewer.setContextMenu(provider);
         //
         
         keyHandler = new KeyHandler();
         keyHandler.put(
                    KeyStroke.getPressed(SWT.DEL, 127, 0),
                    getActionRegistry().getAction(ActionFactory.DELETE.getId()));
         keyHandler.put(
                    KeyStroke.getPressed('+', SWT.KEYPAD_ADD, 0),
                    getActionRegistry().getAction(GEFActionConstants.ZOOM_IN));
         keyHandler.put(
                    KeyStroke.getPressed('-', SWT.KEYPAD_SUBTRACT, 0),
                    getActionRegistry().getAction(GEFActionConstants.ZOOM_OUT));
         
         //zoom handler keyboard shortcut
         viewer.setProperty(
                   MouseWheelHandler.KeyGenerator.getKey(SWT.NONE),
                   MouseWheelZoomHandler.SINGLETON);
         viewer.setKeyHandler(keyHandler);


	}

	@Override
	public void doSave(IProgressMonitor monitor) {
		// TODO Auto-generated method stub
	}

	@Override
	protected void initializeGraphicalViewer() {
	     GraphicalViewer viewer = getGraphicalViewer();
	     model = CreateCanvas();
	     viewer.setContents(model);
	     viewer.addDropTargetListener(new MyTemplateTransferDropTargetListener(viewer));
	}
	
	@Override
	protected void initializePaletteViewer() {
	     super.initializePaletteViewer();
	     getPaletteViewer().addDragSourceListener(
	                 new TemplateTransferDragSourceListener(getPaletteViewer()));
	}


    public Object getAdapter(Class type) {
        if (type == ZoomManager.class)
               return ((ScalableRootEditPart)getGraphicalViewer().getRootEditPart()).getZoomManager();
        if (type == IContentOutlinePage.class)
               return new OutlinePage();
        
        return super.getAdapter(type);
   }
    
    /**This function creates a palette tree with tools that can manipulate objects
     * in the editor.
     * 
     * @return Returns the palette populated basic with tools
     */
    @Override
    protected PaletteRoot getPaletteRoot() {
         //setting the palette
         PaletteRoot root = new PaletteRoot();
         // creating a group for manipulation tools
         PaletteGroup manipGroup = new PaletteGroup("Object manipulation");
         root.add(manipGroup);
         //select tool & marquee
         SelectionToolEntry selectionToolEntry = new SelectionToolEntry();
         manipGroup.add(selectionToolEntry);
         manipGroup.add(new MarqueeToolEntry());
         PaletteSeparator sep2 = new PaletteSeparator();
         root.add(sep2);
         PaletteGroup instGroup = new PaletteGroup("Elements creation");
         root.add(instGroup);
         //adding elements that can be added to the editor's canvas
         instGroup.add(new CombinedTemplateCreationEntry("Root", "Tool to add a new Root",
                    Root.class, new NodeCreationFactory(Root.class),
                    null, null));
         instGroup.add(new CombinedTemplateCreationEntry("Site", "Tool to add a new Site",
                 	Site.class, new NodeCreationFactory(Site.class),
                 	null, null));
         instGroup.add(new CombinedTemplateCreationEntry("Place", "Tool to add a new Place",
                 	Site.class, new NodeCreationFactory(Place.class),
                 	null, null));
         
         root.setDefaultEntry(selectionToolEntry);
         return root;
    }
    
    public void createActions() {
        super.createActions();
        IAction action = new RenameAction(this);
        ActionRegistry registry = getActionRegistry();
        action = new CopyNodeAction(this);
        registry.registerAction(action);
        getSelectionActions().add(action.getId());
        action = new PasteNodeAction(this);
     registry.registerAction(action);
     getSelectionActions().add(action.getId());
   }




}
